package com.example.yimai.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.yimai.dto.OrderRequestDTO;
import com.example.yimai.dto.PageResponseDTO;
import com.example.yimai.entity.Order;
import com.example.yimai.entity.OrderDetail;
import com.example.yimai.entity.Product;
import com.example.yimai.mapper.OrderDetailMapper;
import com.example.yimai.mapper.OrderMapper;
import com.example.yimai.mapper.ProductMapper;
import com.example.yimai.repository.OrderRepository;
import com.example.yimai.repository.ProductRepository;
import com.example.yimai.service.OrderService;
import com.example.yimai.utils.ESUtil;
import com.example.yimai.utils.JWTUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JWTUtil jwtUtil;

    @Override
    public List<OrderDetail> getDetails(String orderId){
        try{
            QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("orderId", orderId);
            return orderDetailMapper.selectList(queryWrapper);
        }catch (Exception e){
            throw new RuntimeException("获取订单详情失败"+e.getMessage());
        }
    }
    
    // 添加一个重载方法，接受Integer类型的orderId
    public List<OrderDetail> getDetails(Integer orderId){
        return getDetails(orderId.toString());
    }

    @Override
    public PageResponseDTO<Order> queryOrder(String token, String keyword, int pageNum, int pageSize) {
        try{
            // 处理Bearer前缀
            if(token != null && token.startsWith("Bearer ")){
                token = token.substring(7);
            }
            
            //构建查询参数
            BoolQueryBuilder params = new BoolQueryBuilder();

            //普通用户仅能查询到自己的订单
            if(jwtUtil.getType(token) == 0) params.must(QueryBuilders.termQuery("loginName", jwtUtil.getLoginName(token)));

            if(keyword == null || keyword.isEmpty())
                params = QueryBuilders.boolQuery();
            else {
                params.should(QueryBuilders.matchQuery("serialNumber", keyword));
                try{
                    LocalDate date = LocalDate.parse(keyword);
                    params.should(QueryBuilders.matchQuery("createTime", date));
                }catch (Exception e){
                    //忽略
                }
            }

            NativeSearchQuery query = ESUtil.buildQuery(pageNum, pageSize, params);
            //获取查询结果
            SearchHits<Order> searchHits = elasticsearchOperations.search(query, Order.class);
            //将结果解析为News数组
            List<Order> orders = searchHits.getSearchHits().stream().map(hit ->{
                Order order = hit.getContent();
                return order;
            }).toList();
            //构建返回对象
            PageResponseDTO<Order> results = new PageResponseDTO<>();
            results.setData(orders);
            results.setTotal((int)searchHits.getTotalHits());
            results.setPageNum(pageNum + 1);
            results.setPageSize(pageSize);
            return results;
        }catch (Exception e){
            throw new RuntimeException("查询订单失败"+e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOrder(String token, List<OrderRequestDTO> requests,String addressId) {
        if(token!= null && token.startsWith("Bearer ")){
            //获取实际的token
            token = token.substring(7);
            try{

                Order order = new Order();
                float costs = 0;
                String serialNumber = generateSerialNumber();

                order.setUserId(Integer.parseInt(jwtUtil.getId(token)));
                order.setLoginName(jwtUtil.getLoginName(token));
                order.setUserAddress(addressId);
                order.setCreateTime(new Date());
                order.setSerialNumber(serialNumber);
                // 先保存订单，用来获取自增的id
                save(order);
                // 生成订单详情
                for (OrderRequestDTO request : requests) {
                    OrderDetail orderDetail = new OrderDetail();
                    Product product = productMapper.selectById(request.getProductId());
                    orderDetail.setProductId(request.getProductId());
                    // 获取商品数量
                    int quantity = Integer.parseInt(request.getQuantity());
                    orderDetail.setQuantity(quantity);
                    // 验证库存，在生成订单时减少对应库存
                    if(product.getStock() - product.getLockedStock() < quantity) {
                        throw new RuntimeException("库存不足");
                    }
                    product.setStock(product.getStock() - quantity);
                    product.setLockedStock(product.getLockedStock() + quantity);
                    productMapper.updateById(product); //减少库存
                    productRepository.save(product);
                    // 获取商品价格
                    float cost = product.getPrice();
                    costs += cost * quantity;

                    orderDetail.setCost(cost * quantity);
                    orderDetail.setOrderId(order.getId());
                    orderDetailMapper.insert(orderDetail);
                }

                // 获取到总价值后更新订单
                order.setCost(costs);
                System.out.println("订单信息"+order);
                updateById(order);

                // 订单信息同步到ES
                orderRepository.save(order);
                // 保存到Redis
                String redisKey = "order:" + serialNumber;
                redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(order), 25, TimeUnit.MINUTES);

                return "success: " + serialNumber;
            }catch (Exception e){
                throw new RuntimeException("创建订单失败"+e.getMessage());
            }
        }else throw new RuntimeException("登录已过期");
    }

    public String pay(String serialNumber){
        String redisKey = "order:" + serialNumber;
        Order order = JSON.parseObject((String) redisTemplate.opsForValue().get(redisKey), Order.class);
        if(order == null) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("serialNumber", serialNumber);
            order = getOne(queryWrapper);
        }
        if(order == null) throw new RuntimeException("订单不存在");
        if(order.getStatus() == 1) throw new RuntimeException("订单已支付");
        if(order.getStatus() == 2) throw new RuntimeException("订单已取消");
        order.setStatus(1);
        updateById(order);  // 使用updateById而不是save
        orderRepository.save(order);
        redisTemplate.delete(redisKey);

        for (OrderDetail orderDetail : getDetails(order.getId())) {
            Product product = productMapper.selectById(orderDetail.getProductId());
            product.setLockedStock(product.getLockedStock() - orderDetail.getQuantity());
            productMapper.updateById(product);
            productRepository.save(product);
        }

        return "success";
    }

    public String cancel(String serialNumber){
        String redisKey = "order:" + serialNumber;
        Order order = JSON.parseObject((String) redisTemplate.opsForValue().get(redisKey), Order.class);
        if(order == null) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("serialNumber", serialNumber);
            order = getOne(queryWrapper);
        }
        if(order == null) throw new RuntimeException("订单不存在");
        if(order.getStatus() == 1) throw new RuntimeException("订单已支付");
        if(order.getStatus() == 2) throw new RuntimeException("订单已取消");

        for (OrderDetail orderDetail : getDetails(order.getId())) {
            Product product = productMapper.selectById(orderDetail.getProductId());
            product.setStock(product.getStock() + orderDetail.getQuantity());
            product.setLockedStock(product.getLockedStock() - orderDetail.getQuantity());
            productMapper.updateById(product);
            productRepository.save(product);
        }
        order.setStatus(2);
        updateById(order);
        orderRepository.save(order);
        redisTemplate.delete(redisKey);

        return "success";
    }

    public String verify(String serialNumber){
        String redisKey = "order:" + serialNumber;
        Order order = JSON.parseObject((String) redisTemplate.opsForValue().get(redisKey), Order.class);
        if(order == null) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("serialNumber", serialNumber);
            order = getOne(queryWrapper);
        }
        if(order == null) throw new RuntimeException("订单不存在");
        if(order.getStatus() == 1) throw new RuntimeException("订单已支付");
        if(order.getStatus() == 2) throw new RuntimeException("订单已取消");
        for (OrderDetail orderDetail : getDetails(order.getId())) {
            Product product = productMapper.selectById(orderDetail.getProductId());
            if(product.getStock() - product.getLockedStock() < orderDetail.getQuantity())return "库存不足";
        }
        return "success";
    }

    @Scheduled(fixedRate = 60000)
    public void handleExpiredOrders(){
        Set<String> keys = redisTemplate.keys("order:*");
        if(keys != null){
            for (String key : keys) {
                String value = (String) redisTemplate.opsForValue().get(key);
                Order order = JSON.parseObject(value, Order.class);
                if(order.getCreateTime().getTime() + 20 * 60000 < System.currentTimeMillis()){
                    cancel(order.getSerialNumber());
                }
            }
        }
    }

    public String generateSerialNumber(){
        String timestamp = String.valueOf(System.currentTimeMillis());
        String random = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        return timestamp + random;
    }
}
